package it.uniroma3.dia;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import it.uniroma3.dia.models.ErrorRatingMovie;
import it.uniroma3.dia.models.RatingMovie;
import it.uniroma3.dia.predictors.AbstractPredictor;
import it.uniroma3.dia.predictors.ItemBasedPredictor;
import it.uniroma3.dia.predictors.ItemBasedPredictor.ItemBasedTuningParameter;
import it.uniroma3.dia.reader.FileRatingMovieRW;
import it.uniroma3.dia.reader.IRatingMovieRW;
import it.uniroma3.dia.training.ErrorWatcher;
import it.uniroma3.dia.utils.Utils;
/** 
*
* @author Daniele D'Andrea
* @author Antonio Gallo
*/
public class ChallengeMain {

	/**
	 * @param args
	 * @throws Exception 
	 */
	public static void main(String[] args) throws Exception {

		if(args.length<2){
			System.out.println("ERRORE: Inserire inputFilePath e outputFilePath");
			return;
		}
		
		String inputPath = System.getProperty("user.dir")+"/"+args[0];
		String outputPath = System.getProperty("user.dir")+"/"+args[1];
		
		if(!new File(inputPath).exists())
		{
			System.out.println("ERRORE: "+inputPath+" non esiste");
			return;
		}
		
		IRatingMovieRW ratingMovieRW = new FileRatingMovieRW(inputPath, outputPath);
		List<RatingMovie> ratingMovies = ratingMovieRW.readRatingMovies();
		
		System.out.println(ratingMovies.size()+" caricati, processamento in corso...");
		
		long startTime = System.currentTimeMillis();
		
		//NUMERO THREAD
		int numberOfThread = 4;
		//
		
		ExecutorService executor = Executors.newFixedThreadPool(numberOfThread);
		CountDownLatch countDownLatch = new CountDownLatch(numberOfThread);

		//TUNING PARAMETER
		int K = 5;
		ItemBasedTuningParameter tuningParameter = ItemBasedPredictor.newItemBasedTuningParameter(10,3,5,10,2,7,8, K);
		//
		
		ConcurrentLinkedQueue<RatingMovie> concurredLinkedQueue = new ConcurrentLinkedQueue<RatingMovie>();
		concurredLinkedQueue.addAll(ratingMovies);
		List<AbstractPredictor> predictors = new ArrayList<AbstractPredictor>();
		
		for(int j = 0; j<numberOfThread; j++){	
			AbstractPredictor itemBasedPrediction = new ItemBasedPredictor(tuningParameter);
			itemBasedPrediction.setCountDownLatch(countDownLatch);
			itemBasedPrediction.setConcurredLinkedQueue(concurredLinkedQueue);
			executor.execute(itemBasedPrediction);
			predictors.add(itemBasedPrediction);
		}

		//WATCHER
		Timer timer = new Timer();
		TimerTask task = new ErrorWatcher(predictors);
		timer.schedule( task, 1000, 1000 );
		//
		
		countDownLatch.await();
		executor.shutdown();

		//WATCHER
		timer.cancel();
		//
		
		System.out.println(ratingMovies.size()+" processati correttamente.");

		long endTime = System.currentTimeMillis();
		long diff = endTime - startTime;
		
		ErrorRatingMovie errorRatingMovie = Utils.calculateErrorMeasure(predictors);
		int total = errorRatingMovie.getTotal();

		System.out.println("tuning = "+tuningParameter.toString());
		System.out.print(total+" record elaborati in "+diff+" ms ("+(double)total/(diff/1000)+" movie\\s).");

		System.out.println(ratingMovies.size()+" scritti correttamente su "+outputPath);
		
		ratingMovieRW.writeRatingMoviesPrediction(ratingMovies);
	}
}
